"""
场景数据库仓储层
"""

import uuid
from datetime import datetime
from typing import List, Optional, Dict, Any

from sqlalchemy import desc
from sqlalchemy.orm import Session, selectinload

from pojo.ai_web_scene import AIWebSceneQueryParams
from pojo.ai_web_scene_model import AIWebSceneModel


class SceneRepository:
    """场景数据库仓储类"""

    def __init__(self, db: Session):
        self.db = db

    def get_by_id(self, scene_id: str) -> Optional[AIWebSceneModel]:
        """根据ID获取场景"""
        return self.db.query(AIWebSceneModel).filter(
            AIWebSceneModel.scene_id == scene_id
        ).first()

    def get_by_id_with_children(self, scene_id: str) -> Optional[AIWebSceneModel]:
        """根据ID获取场景（包含子节点）"""
        return self.db.query(AIWebSceneModel).options(
            selectinload(AIWebSceneModel.children)
        ).filter(
            AIWebSceneModel.scene_id == scene_id
        ).first()

    def get_root_nodes(self, query_params: AIWebSceneQueryParams) -> List[AIWebSceneModel]:
        """获取根节点列表"""
        query = self.db.query(AIWebSceneModel).filter(
            AIWebSceneModel.parent_id.is_(None)
        )

        # 应用过滤条件
        query = self._apply_filters(query, query_params)

        # 如果需要包含子节点，预加载关系
        if query_params.include_children:
            query = query.options(selectinload(AIWebSceneModel.children))

        return query.order_by(AIWebSceneModel.sort_order).all()

    def get_children(self, parent_id: str) -> List[AIWebSceneModel]:
        """获取直接子节点"""
        return self.db.query(AIWebSceneModel).filter(
            AIWebSceneModel.parent_id == parent_id
        ).order_by(AIWebSceneModel.sort_order).all()

    def get_all_descendants(self, scene_id: str) -> List[AIWebSceneModel]:
        """获取所有后代节点"""
        scene = self.get_by_id_with_children(scene_id)
        if not scene:
            return []

        descendants = []
        self._collect_descendants(scene, descendants)
        return descendants

    def get_ancestors(self, scene_id: str) -> List[AIWebSceneModel]:
        """获取所有祖先节点"""
        ancestors = []
        current = self.get_by_id(scene_id)

        while current and current.parent_id:
            parent = self.get_by_id(current.parent_id)
            if parent:
                ancestors.insert(0, parent)
                current = parent
            else:
                break

        return ancestors

    def get_scene_path(self, scene_id: str) -> List[AIWebSceneModel]:
        """获取场景路径（从根到当前节点）"""
        scene = self.get_by_id(scene_id)
        if not scene:
            return []

        path = [scene]
        ancestors = self.get_ancestors(scene_id)
        return ancestors + path

    def create(self, scene_data: Dict[str, Any]) -> AIWebSceneModel:
        """创建场景"""
        # 生成唯一ID
        if 'scene_id' not in scene_data:
            scene_data['scene_id'] = str(uuid.uuid4())

        # 计算路径和层级
        if scene_data.get('parent_id'):
            parent = self.get_by_id(scene_data['parent_id'])
            if parent:
                scene_data['node_level'] = parent.node_level + 1
                scene_data[
                    'node_path'] = f"{parent.node_path}/{parent.scene_id}" if parent.node_path != "/" else f"/{parent.scene_id}"
            else:
                raise ValueError(f"父节点不存在: {scene_data['parent_id']}")
        else:
            scene_data['node_level'] = 0
            scene_data['node_path'] = "/"

        # 设置创建时间
        scene_data['create_time'] = datetime.now()

        scene = AIWebSceneModel(**scene_data)
        self.db.add(scene)
        self.db.commit()
        self.db.refresh(scene)
        return scene

    def update(self, scene_id: str, update_data: Dict[str, Any]) -> Optional[AIWebSceneModel]:
        """更新场景"""
        scene = self.get_by_id(scene_id)
        if not scene:
            return None

        # 乐观锁检查
        if 'version' in update_data:
            if scene.version != update_data['version']:
                raise ValueError("版本冲突，数据已被其他用户修改")

        # 更新字段
        for key, value in update_data.items():
            if key != 'version' and hasattr(scene, key):
                setattr(scene, key, value)

        # 更新修改时间和版本号
        scene.modify_time = datetime.now()
        scene.version += 1

        self.db.commit()
        self.db.refresh(scene)
        return scene

    def delete(self, scene_id: str) -> bool:
        """删除场景（级联删除子节点）"""
        scene = self.get_by_id_with_children(scene_id)
        if not scene:
            return False

        # SQLAlchemy会自动处理级联删除
        self.db.delete(scene)
        self.db.commit()
        return True

    def move_scene(self, scene_id: str, new_parent_id: Optional[str]) -> Optional[AIWebSceneModel]:
        """移动场景到新的父节点"""
        scene = self.get_by_id_with_children(scene_id)
        if not scene:
            return None

        # 验证新父节点
        if new_parent_id:
            new_parent = self.get_by_id(new_parent_id)
            if not new_parent:
                raise ValueError(f"新父节点不存在: {new_parent_id}")

            # 检查是否会形成循环引用
            if self._would_create_cycle(scene_id, new_parent_id):
                raise ValueError("移动操作会形成循环引用")

        # 更新场景信息
        scene.parent_id = new_parent_id

        # 重新计算路径和层级
        if new_parent_id:
            new_parent = self.get_by_id(new_parent_id)
            scene.node_level = new_parent.node_level + 1
            scene.node_path = f"{new_parent.node_path}/{new_parent.scene_id}" if new_parent.node_path != "/" else f"/{new_parent.scene_id}"
        else:
            scene.node_level = 0
            scene.node_path = "/"

        # 递归更新所有子节点的路径和层级
        self._update_children_path_and_level(scene)

        self.db.commit()
        self.db.refresh(scene)
        return scene

    def count_all(self, query_params: AIWebSceneQueryParams) -> int:
        """统计场景总数"""
        query = self.db.query(AIWebSceneModel)
        query = self._apply_filters(query, query_params)
        return query.count()

    def get_max_depth(self) -> int:
        """获取最大深度"""
        max_level = self.db.query(AIWebSceneModel.node_level).order_by(
            desc(AIWebSceneModel.node_level)
        ).first()
        return max_level[0] if max_level else 0

    def _apply_filters(self, query, query_params: AIWebSceneQueryParams):
        """应用查询过滤条件"""
        if query_params.scene_name:
            query = query.filter(
                AIWebSceneModel.scene_name.like(f"%{query_params.scene_name}%")
            )

        if query_params.scene_status:
            query = query.filter(
                AIWebSceneModel.scene_status == query_params.scene_status
            )

        if query_params.creator:
            query = query.filter(
                AIWebSceneModel.creator.like(f"%{query_params.creator}%")
            )

        if query_params.parent_id:
            query = query.filter(
                AIWebSceneModel.parent_id == query_params.parent_id
            )

        if query_params.max_depth is not None:
            query = query.filter(
                AIWebSceneModel.node_level <= query_params.max_depth
            )

        return query

    def _collect_descendants(self, scene: AIWebSceneModel, descendants: List[AIWebSceneModel]):
        """递归收集所有后代节点"""
        for child in scene.children:
            descendants.append(child)
            self._collect_descendants(child, descendants)

    def _would_create_cycle(self, scene_id: str, new_parent_id: str) -> bool:
        """检查移动操作是否会创建循环引用"""
        current = self.get_by_id(new_parent_id)
        while current:
            if current.scene_id == scene_id:
                return True
            current = self.get_by_id(current.parent_id) if current.parent_id else None
        return False

    def _update_children_path_and_level(self, parent: AIWebSceneModel):
        """递归更新子节点的路径和层级"""
        for child in parent.children:
            child.node_level = parent.node_level + 1
            child.node_path = f"{parent.node_path}/{parent.scene_id}" if parent.node_path != "/" else f"/{parent.scene_id}"
            self._update_children_path_and_level(child)

    def get_tree_with_filters(self, query_params: AIWebSceneQueryParams) -> List[AIWebSceneModel]:
        """获取过滤后的完整树结构"""
        # 首先获取所有符合条件的节点
        query = self.db.query(AIWebSceneModel)
        query = self._apply_filters(query, query_params)

        if query_params.include_children:
            query = query.options(selectinload(AIWebSceneModel.children))

        all_nodes = query.all()

        # 构建树形结构
        node_map = {node.scene_id: node for node in all_nodes}
        root_nodes = []

        for node in all_nodes:
            if node.parent_id is None:
                root_nodes.append(node)
            elif node.parent_id in node_map:
                parent = node_map[node.parent_id]
                if node not in parent.children:
                    parent.children.append(node)

        # 按排序字段排序
        root_nodes.sort(key=lambda x: x.sort_order)
        for node in all_nodes:
            node.children.sort(key=lambda x: x.sort_order)

        return root_nodes
